package com.bite.judge.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bite.api.domain.UserExeResult;
import com.bite.api.domain.dto.JudgeSubmitDTO;
import com.bite.api.domain.vo.UserQuestionResultVO;
import com.bite.common.core.constants.Constants;
import com.bite.common.core.constants.JudgeConstants;
import com.bite.common.core.enums.CodeRunStatus;
import com.bite.common.core.utils.ThreadLocalUtil;
import com.bite.judge.domain.SandBoxExecuteResult;
import com.bite.judge.domain.UserSubmit;
import com.bite.judge.manager.UserSubmitCacheManager;
import com.bite.judge.mapper.UserSubmitMapper;
import com.bite.judge.service.IJudgeService;
import com.bite.judge.service.ISandboxPoolService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedList;
import java.util.List;

@Service
public class JudgeServiceService implements IJudgeService {

//    @Autowired
//    private ISandboxService sandboxService;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private ISandboxPoolService sandboxPoolService;

    @Autowired
    private UserSubmitCacheManager userSubmitCacheManager;

    @Override
    public UserQuestionResultVO doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        // 先编译 再判断
//        SandBoxExecuteResult sandBoxExecuteResult =
//                sandboxService.doJavaCode(judgeSubmitDTO);

        SandBoxExecuteResult sandBoxExecuteResult =
                sandboxPoolService.doJavaCode(judgeSubmitDTO);
        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO();
        if (sandBoxExecuteResult != null && CodeRunStatus.isSuccess(sandBoxExecuteResult.getRunStatus())) {
            // 执行成功 判断时间、空间、运行结果
            userQuestionResultVO = getUserQuestionResultVO(judgeSubmitDTO, sandBoxExecuteResult);
        } else {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            if (sandBoxExecuteResult == null) {
                userQuestionResultVO.setErrMsg(CodeRunStatus.UNKNOWN_FAILED.getMsg());
            } else {
                userQuestionResultVO.setErrMsg(sandBoxExecuteResult.getExeMessage());
            }
        }
        updateLastUserSubmit(judgeSubmitDTO, userQuestionResultVO);
        return userQuestionResultVO;
    }

    private static UserQuestionResultVO getUserQuestionResultVO(JudgeSubmitDTO judgeSubmitDTO, SandBoxExecuteResult sandBoxExecuteResult) {
        // 执行成功 判断时间、空间、运行结果
        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
        List<String> outputList = judgeSubmitDTO.getOutputList();
        if (exeOutputList.size() != outputList.size()) {
            return UserQuestionResultVO.err(CodeRunStatus.FAILED);
        }
        List<UserExeResult> exeResultList = new LinkedList<>();
        boolean isPass = isPass(judgeSubmitDTO, sandBoxExecuteResult, exeResultList);
        if (!isPass) {
            return UserQuestionResultVO.err(CodeRunStatus.NOT_ALL_PASSED, exeResultList);
        }
        if (judgeSubmitDTO.getTimeLimit() < sandBoxExecuteResult.getUseTime()) {
            return UserQuestionResultVO.err(CodeRunStatus.OUT_OF_TIME, exeResultList);
        }
        if (judgeSubmitDTO.getSpaceLimit() < sandBoxExecuteResult.getUseMemory()) {
            return UserQuestionResultVO.err(CodeRunStatus.OUT_OF_MEMORY, exeResultList);
        }
        // 成功
        Integer score = getUserQuestionScore(judgeSubmitDTO);
        return UserQuestionResultVO.success(exeResultList, score);
    }

    // 获取正确情况下的分数
    private static Integer getUserQuestionScore(JudgeSubmitDTO judgeSubmitDTO) {
        // 将来可以通过执行时间等情况来经行判分
        return judgeSubmitDTO.getDifficulty() * JudgeConstants.DEFAULT_SCORE;
    }

    private static boolean isPass(JudgeSubmitDTO judgeSubmitDTO,
                                  SandBoxExecuteResult sandBoxExecuteResult,
                                  List<UserExeResult> exeResultList) {
        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
        List<String> outputList = judgeSubmitDTO.getOutputList();
        boolean isPass = true;
        List<String> inputList = judgeSubmitDTO.getInputList();
        for (int index = 0; index < exeOutputList.size() && isPass; index++) {
            String output = outputList.get(index);
            String exeOutput = exeOutputList.get(index);
            String input = inputList.get(index);
            exeResultList.add(new UserExeResult(input, output, exeOutput));
            isPass = output.equals(exeOutput);
        }
        return isPass;
    }

    private void updateLastUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        // 更新最后一次的执行结果
        UserSubmit userSubmit = new UserSubmit();
        BeanUtil.copyProperties(userQuestionResultVO, userSubmit);
        BeanUtil.copyProperties(judgeSubmitDTO, userSubmit);
        userSubmit.setProgramCode(judgeSubmitDTO.getUserCode());
        userSubmit.setResult(userQuestionResultVO.getErrMsg());
        userSubmit.setCaseJudgeRes(JSONUtil.toJsonStr(userQuestionResultVO.getExeResultList()));
        ThreadLocalUtil.set(Constants.THREAD_LOCAL_USER_ID, judgeSubmitDTO.getUserId());
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, judgeSubmitDTO.getUserId())
                .eq(UserSubmit::getQuestionId, judgeSubmitDTO.getQuestionId())
                .eq(judgeSubmitDTO.getExamId() != null, UserSubmit::getExamId, judgeSubmitDTO.getExamId())
                .isNull(judgeSubmitDTO.getExamId() == null, UserSubmit::getExamId)
        );
        userSubmitMapper.insert(userSubmit);
        // 在缓存中更新
        userSubmitCacheManager.refreshUserSubmit(userSubmit);
    }
}
